//==================================================================
//  Copyright (C) 2006  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
///
///
///
///
//==================================================================

#ifndef CAPTURE_WDM_H
#define CAPTURE_WDM_H

#include <windows.h>
#include <mmsystem.h>
#include <atlbase.h>
#include <stdio.h>
#include <dshow.h>
#include <qedit.h>
#include "mtype.h"
#include "pcapture_base.h"

//==================================================================
class CaptureWDM : public CaptureBase
{
	static const int MAX_DEVICES = 10;

private:
	IFilterGraph2			*_filtergraph_2_p;
	ICaptureGraphBuilder2	*_graph_2_p;		// Helps to render capture graphs
	IBaseFilter				*_src_bfilterp;
	IBaseFilter				*_grab_bfilterp;
	IBaseFilter				*_null_bfilterp;
	ISampleGrabber			*_grabberp;
	IMediaControl			*_mediacontrolp;


	int			_w, _h;
	int			_nbits;
	float		_fps;

	int			_input_format;
	int			_data_y_w, _data_y_h;
	int			_data_uv_w, _data_uv_h;

	int			_supersample_flg;
	int			_capture_enabled_flg;
	int			_capture_suspend_flg;

	double		_last_captured_ms;

	void		(*_frame_callback)( u_char *, int, int );

	volatile int	_user_lock_w;

	//volatile int	data_lock_w;
	//volatile int	data_lock_r;
	int			_data_mutex_locked;
	u_int		_data_size;
	u_char		*_data_nrp[2];
	u_char		*_data_rawp[2];
	int			_data_idx;
	int			_last_nr_data_idx;

	HANDLE		_wlock_mutexh[2];

	TCHAR		_driver_names[MAX_DEVICES][80];
	TCHAR		_driver_versions[MAX_DEVICES][40];
	int			_driver_flags[MAX_DEVICES];
	int			_driver_forced_bits[MAX_DEVICES];
	int			_n_drivers;
	int			_cap_idle_frame_cnt;
	int			_frame_cnt;

	int			_driver_select_cnt;

	class CSampleGrabberCB	*_samplegrabbercbp;

	int			_cur_sel_device;



public:
	CaptureWDM();
	~CaptureWDM();

	virtual int		Setup( int dr_num, int w, int h, float fps, int flags );
	virtual int		BeginCapture();
	virtual void	SuspendCapture( int yesno );
	virtual int		IsSuspended();
	virtual int		CheckNextFrame();
	virtual void	EndCapture();

	//virtual void	driver_dialog_videosource() {}
	virtual int		GetDriverN();
	virtual TCHAR	*GetDriverName(int i);
	virtual TCHAR	*GetDriverVersion(int i);

	virtual int		rgb_buffer_get_width();
	virtual int		rgb_buffer_get_height();
	virtual PError	rgb_buffer_copy( u_char *dest_rgb_datap );
	virtual PError	rgbraw_buffer_copy( u_char *dest_rgb_datap );

private:
	void			addDriver( const wchar_t *namep );
	IBaseFilter		*makeFilterFromMoniker(IMoniker *pMoniker);

	HRESULT			dshowInitialize();
	void			dshowRelease();
	int				driverAddEnumCBack( IMoniker *pMoniker );
	static int		driverAddEnumCBack_s( void *userdatap, IMoniker *pMoniker )
					{
						return ((CaptureWDM *)userdatap)->driverAddEnumCBack( pMoniker );
					}
	void			dshowCaptureSetup( IMoniker *pMoniker, int w, int h ) throw(...);
	void			selectBestMatch( IBaseFilter *src_bfilterp, int w, int h, int depth ) throw(...);
	void			dshowCaptureCleanup();
	void			dshowSetupBuffer()  throw(...);
	void			dshowUpdateBuffer( int w, int h ) throw(...);

	int				driverSelectEnumCBack( IMoniker *pMoniker );
	static int		driverSelectEnumCBack_s( void *userdatap, IMoniker *pMoniker )
					{
						return ((CaptureWDM *)userdatap)->driverSelectEnumCBack( pMoniker );
					}

	HRESULT			dshowFrameCBack( double SampleTime, IMediaSample *pSample );
	static HRESULT	dshowFrameCBack_s( void *userdatap, double SampleTime, IMediaSample *pSample )
					{
						return ((CaptureWDM *)userdatap)->dshowFrameCBack( SampleTime, pSample );
					}

	int				lockBuffer( int buff_idx, int read_msk=0, int write_msk=0 );
	void			unlockBuffer( int buff_idx, int read_msk=0, int write_msk=0 );
	void			fillEmptyBuffer( u_char *dest_rgb_datap, int off=0 );

	bool			isUsingSimulated() const {	return _cur_sel_device == _n_drivers-1; }

};


#endif